// Author: Bjorn Schobben, Domien Nowicki

#include <assert.h>
#include "Raycaster.h"
#include "Vector.h"
#include "Ray.h"
#include "Texture.h"
#include "Slice.h"
#include "Minimap.h"



Raycaster::Raycaster()
{
	// Initialize camera with the world
	camera.SetWorld(world);
}

Raycaster::~Raycaster()
{

}

void Raycaster::SetWorld(const World& w)
{
	// Copy world
	world = w;

	// And initialize camera again
	camera.SetWorld(world);
}

// Render entire screen
void Raycaster::Render()
{
	Vector direction = camera.GetDirection();
	Vector plane = camera.GetCameraPlane();
	Vector eyepoint = camera.GetEyepoint();

	unsigned int height = GetHeight();

	// Initialize slice with the screen's height (will not change during rendering operation)
	Slice slice(height);



	for(int x=0; x<GetWidth(); x++)
	{
		// Get x ratio based on screen width
		Scalar cameraX = (Scalar)(2*x) / GetWidth() - 1;
		// Get horizontal ray for this screen's x coordinate
		Vector rayDirection = direction + plane*cameraX;

		// "Cast" ray
		Ray ray(eyepoint, rayDirection, world);

		// Render slice into buffer for this ray
		slice.Initialize(ray, eyepoint, world);

		// And really render slice pixels now
		for(unsigned int y = 0; y < height; y++)
		{
			SetPixel(x, y, slice.GetPixel(y));
		}
	}

	// And also render the minimap
	RenderMinimap();
}

void Raycaster::RenderMinimap()
{
	Pixel eyeColor(0, 255, 0);
	Pixel wallColor(255, 255, 0);
	Pixel mapColor(20, 20, 70);
	
	Minimap minimap(world, GetWidth(), GetHeight(), camera, mapColor, wallColor, eyeColor);

	// Calculate x,y offset for minimap for positioning it on the screen
	int offsetX = GetWidth()- 10 - minimap.GetWidth();
	int offsetY = GetHeight() - 10 - minimap.GetWidth();

	// Get field of view polygon, color it, and offset it
	Poly radarViewPoly = minimap.GetViewPoly();
	radarViewPoly.SetColor(Pixel(255, 255, 255, 150));
	radarViewPoly.AddOffset(Vector(offsetX, offsetY));

	// Render the minimap's pixels
	for(int j = 0; j < minimap.GetHeight(); j++)
	{
		for(int i = 0; i < minimap.GetWidth(); i++)
		{
			SetPixel(offsetX+i, offsetY+j, minimap.GetPixel(i, j));
		}
	}

	// Render the polygon
	DrawPolygon(radarViewPoly);
}

// Positioning operations
void Raycaster::TurnLeft()
{
	camera.TurnLeft();
}

void Raycaster::TurnRight()
{
	camera.TurnRight();
}

void Raycaster::TurnLeft(const Scalar& ratio)
{
	camera.TurnLeft(ratio);
}

void Raycaster::TurnRight(const Scalar& ratio)
{
	camera.TurnRight(ratio);
}

void Raycaster::MoveForward()
{
	camera.MoveForward();
}

void Raycaster::MoveBackward()
{
	camera.MoveBackward();
}

void Raycaster::MoveForward(const Scalar& ratio)
{
	camera.MoveForward(ratio);
}

void Raycaster::MoveBackward(const Scalar& ratio)
{
	camera.MoveBackward(ratio);
}
